home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume15 / ck < prev    next >
Encoding:
Internet Message Format  |  1988-05-30  |  11.1 KB

  1. Subject:  v15i025:  Check mailboxes for new mail
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Wayne Mesard <mesard@bbn.com>
  7. Posting-number: Volume 15, Issue 25
  8. Archive-name: ck
  9.  
  10. These programs examine mailbox files and report the sender and subject of
  11. each message contained in the file.  Although there are dozens of similar
  12. programs wandering around UNIX land, many don't work on common system
  13. configurations.  (E.g., from only works if the mailbox lives in
  14. /usr/spool/mail ; buff and rcvalert don't get along well with the SunView
  15. windows; etc.)
  16.  
  17. #! /bin/sh
  18. # This is a shell archive.  Remove anything before this line, then unpack
  19. # it by saving it into a file and typing "sh file".  To overwrite existing
  20. # files, type "sh file -c".  You can also feed this as standard input via
  21. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  22. # will see the following message at the end:
  23. #        "End of shell archive."
  24. # Contents:  Makefile ck.c ck.man ckd.man wsm_types.h
  25. # Wrapped by rsalz@fig.bbn.com on Tue May 31 16:20:42 1988
  26. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  27. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  28.   echo shar: Will not clobber existing file \"'Makefile'\"
  29. else
  30. echo shar: Extracting \"'Makefile'\" \(155 characters\)
  31. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  32. BIN = ../bin/
  33. CFLAGS = -O
  34. X
  35. all: ck ckd
  36. X
  37. ck: $(BIN)ck
  38. X$(BIN)ck: ck.c
  39. X    $(CC) $(CFLAGS) ck.c -o $(BIN)ck
  40. X
  41. ckd: $(BIN)ckd
  42. X$(BIN)ckd:
  43. X    ln -s $(BIN)ck $(BIN)ckd
  44. END_OF_FILE
  45. if test 155 -ne `wc -c <'Makefile'`; then
  46.     echo shar: \"'Makefile'\" unpacked with wrong size!
  47. fi
  48. # end of 'Makefile'
  49. fi
  50. if test -f 'ck.c' -a "${1}" != "-c" ; then 
  51.   echo shar: Will not clobber existing file \"'ck.c'\"
  52. else
  53. echo shar: Extracting \"'ck.c'\" \(4618 characters\)
  54. sed "s/^X//" >'ck.c' <<'END_OF_FILE'
  55. X/**************************************************************************
  56. X *      ck{,d}: an incoming mail monitor.
  57. X *      Copyright (c) 1988 Wayne Mesard                                   *
  58. X *                                                                        *
  59. X *      This is free software.  It may be reproduced, retransmitted,      *
  60. X *      redistributed and otherwise propogated at will, provided that     *
  61. X *      this notice remains intact and in place.                          *
  62. X *                                                                        *
  63. X *      Direct all bug reports and comments to mesard@BBN.COM.            *
  64. X *                                                                        *
  65. X **************************************************************************/
  66. X
  67. X
  68. X#include <stdio.h>
  69. X#include <strings.h>
  70. X#include <sys/types.h>
  71. X#include <sys/stat.h>
  72. X#include <ctype.h>
  73. X#include "wsm_types.h"
  74. X
  75. X
  76. main(argc, argv)
  77. int argc;
  78. char *argv[];
  79. X{
  80. X    extern char *getenv();
  81. X    extern int atoi();
  82. X    extern int getppid();    /* For parent check. */
  83. X    int check_box();
  84. X    time_t last_write();
  85. X    
  86. X    int i, c;
  87. X    int interval = 120;
  88. X    FILE *out_device = NULL;
  89. X    boolean verbose = false;
  90. X    int ppid;            /* For parent check. */
  91. X    
  92. X    char *ptr, mailbox[256];
  93. X    time_t curr, old_mtime;
  94. X
  95. X
  96. X    for (i=0; ++i<argc && argv[i][0]=='-';)
  97. X    switch (argv[i][1]) {
  98. X      case 'v':
  99. X        verbose = true;
  100. X        break;
  101. X      case 'i':
  102. X        interval = atoi(argv[i]+2);
  103. X        break;
  104. X      case 'o':
  105. X            if (out_device != NULL)
  106. X                fclose(out_device);
  107. X            if (i+1<argc)
  108. X        if ((out_device = fopen(argv[++i], "a"))==NULL) {
  109. X            perror(argv[i]+2);
  110. X            exit(-1);
  111. X        }
  112. X            break;
  113. X    }
  114. X
  115. X    mailbox[0] = '\0';
  116. X    if (i<argc)
  117. X    strcpy(mailbox, argv[i]);
  118. X
  119. X    if (mailbox[0] == '\0')
  120. X    if (ptr = getenv("MAIL"))
  121. X        (void) strcpy(mailbox, ptr);
  122. X    else {
  123. X        (void) strcpy(mailbox, getenv("HOME"));
  124. X        (void) strcat(mailbox, "/mailbox");
  125. X    }
  126. X     
  127. X    if (!strcmp("ck", argv[0]+strlen(argv[0])-2)) {
  128. X    if ((c=check_box(mailbox, (out_device?out_device:stdout), verbose, false))==0)
  129. X        printf("No new messages.\n");
  130. X    exit(c);
  131. X    }
  132. X
  133. X    ppid = getppid();
  134. X    if (fork())
  135. X    exit(0);
  136. X
  137. X    old_mtime = last_write(mailbox);
  138. X    while(1) {
  139. X    if (old_mtime < (curr=last_write(mailbox))) {
  140. X        old_mtime = curr;
  141. X        (void) check_box(mailbox, (out_device?out_device:stderr), verbose, true);
  142. X    }
  143. X
  144. X    sleep(interval);
  145. X
  146. X    /* Check to see if parent has died (e.g., on logout).
  147. X     * Commit suicide if it has.
  148. X     * There must be a better way to do this! (setpgrp?)
  149. X     */
  150. X    if (kill(ppid, 0))
  151. X        exit(0);
  152. X    }
  153. X}
  154. X
  155. X
  156. X
  157. time_t last_write(fn)
  158. char *fn;
  159. X{
  160. X  struct stat stbuf;
  161. X
  162. X  stat(fn, &stbuf);
  163. X  return((time_t) stbuf.st_mtime);
  164. X}
  165. X
  166. X
  167. X#define BUFSIZE 100
  168. X#define FROM_FIELD_LEN 19
  169. X#define SUBJ_FIELD_LEN 21
  170. X#if (FROM_FIELD_LEN != 19 || SUBJ_FIELD_LEN != 21)
  171. X    HEY! Fix the fprintf() line below.
  172. X#endif
  173. X#if (BUFSIZE != 100)
  174. X    HEY! Fix the fscanf() line below.
  175. X#endif
  176. X
  177. int check_box(fn, out_device, verbose, bell)
  178. char *fn;
  179. XFILE *out_device;
  180. boolean verbose, bell;
  181. X{
  182. X    extern char *ctime();
  183. X    void nonwhitecpy();
  184. X    static char *margin =
  185. X    "+---------------------------------------------+\n";
  186. X    FILE *mbox;
  187. X    char *devname;
  188. X    char s[BUFSIZE], from_field[FROM_FIELD_LEN], 
  189. X         subj_field[SUBJ_FIELD_LEN];
  190. X    int headers = 0, readstat = 0;
  191. X    int count = 0;
  192. X
  193. X    if (mbox = fopen(fn, "r")) {
  194. X    while ((readstat=fscanf(mbox, "%100[^\n]", s)) != EOF) {
  195. X        (void) getc(mbox);
  196. X
  197. X        if (headers) {
  198. X        if (readstat==0) {
  199. X            headers = 0;
  200. X            if (count==0)
  201. X            fprintf(out_device, "%c%s",
  202. X                   (bell ? '\007' : '\0'), margin);
  203. X            fprintf(out_device, "|%2d: %-18.18s{}%-20.20s |\n", 
  204. X                ++count, from_field, subj_field);
  205. X        }
  206. X        else if (!strncmp(s, "From:", 5))
  207. X            nonwhitecpy(from_field, s+6, FROM_FIELD_LEN);
  208. X
  209. X        else if (!strncmp(s, "Subject:", 8))
  210. X            nonwhitecpy(subj_field, s+9, SUBJ_FIELD_LEN);
  211. X        }
  212. X        else if (!strncmp(s,"\001\001\001\001", 4)) {
  213. X        headers = 1;
  214. X        subj_field[0] = from_field[0] = '\0';
  215. X        }
  216. X    }
  217. X    fclose(mbox);
  218. X    if (count)
  219. X        fprintf(out_device, margin);
  220. X    }
  221. X    else
  222. X    verbose = true;
  223. X
  224. X    if (verbose) {
  225. X    struct stat stbuf;
  226. X
  227. X    if (stat(fn, &stbuf))
  228. X        perror(fn);
  229. X    else
  230. X        fprintf(out_device, 
  231. X            "[%s] Size: %d chars.\nLast modified: %s", 
  232. X            fn,
  233. X            stbuf.st_size, 
  234. X            ctime((long *)&stbuf.st_mtime));
  235. X    return(-1);
  236. X    }
  237. X    return(count);
  238. X
  239. X    
  240. X}
  241. X
  242. X
  243. X
  244. void
  245. nonwhitecpy(d, s, dsize)
  246. register char *d, *s;
  247. int dsize;
  248. X{
  249. X    register char *dend = d+dsize;
  250. X    s--;
  251. X    while (isspace(*++s));
  252. X    while ((*d++ = *s++) && (d<dend));
  253. X}
  254. END_OF_FILE
  255. if test 4618 -ne `wc -c <'ck.c'`; then
  256.     echo shar: \"'ck.c'\" unpacked with wrong size!
  257. fi
  258. # end of 'ck.c'
  259. fi
  260. if test -f 'ck.man' -a "${1}" != "-c" ; then 
  261.   echo shar: Will not clobber existing file \"'ck.man'\"
  262. else
  263. echo shar: Extracting \"'ck.man'\" \(3012 characters\)
  264. sed "s/^X//" >'ck.man' <<'END_OF_FILE'
  265. X.TH CK 1L "4 February 1988" " " " "
  266. X
  267. X.SH NAME
  268. ck, ckd - report newly arrived mail
  269. X
  270. X.SH SYNOPSIS
  271. X.B ck
  272. X[ 
  273. X.B \-v
  274. X] 
  275. X[ 
  276. X.B \-o 
  277. X.I outfile 
  278. X]
  279. X[ 
  280. X.I mailbox 
  281. X]
  282. X.br
  283. X.B ckd
  284. X[ 
  285. X.B \-v
  286. X] 
  287. X[ 
  288. X.B \-o 
  289. X.I outfile 
  290. X]
  291. X[ 
  292. X.BI \-i interval 
  293. X] 
  294. X[ 
  295. X.I mailbox 
  296. X]
  297. X
  298. X.SH DESCRIPTION
  299. X.I ck 
  300. and 
  301. X.I ckd
  302. are, respectively, the command line and daemon versions of a program
  303. to monitor your incoming mail.  They examine mailbox files and report
  304. the sender and subject of each message contained in the file.  If a
  305. mailbox is not specified, 
  306. X.I $HOME/mailbox
  307. will be used.  If the user does not have read access to
  308. the mailbox, an attempt will be made to report the size of the
  309. file and when it was last modified.  This allows the user to check
  310. if someone else recently received mail.
  311. X
  312. Although there are dozens of similar programs wandering around UNIX
  313. land, many don't work on common system configurations.  (E.g.,
  314. X.I from 
  315. only works if the mailbox lives in 
  316. X.BR /usr/spool/mail ";  "
  317. X.I biff 
  318. and 
  319. X.I rcvalert
  320. don't get along well with the SunView windows; etc.)  
  321. X.I ck 
  322. and 
  323. X.I ckd 
  324. contribute to this parochial mass, since currently they only work
  325. with MMDF format files (or more specifically, files in which
  326. each message is separated by a line containing four Control-A's).
  327. But they do try to be more flexible about how they notify the user.
  328. X
  329. X.I ck 
  330. reports the status of the mailbox once and exits.  
  331. X.I ckd 
  332. runs in the background and reports whenever it notices that 
  333. the mailbox has been modified.  
  334. X.I ckd 
  335. terminates automatically when it sees that the process from which it
  336. was invoked has also terminated.  For example, if you run
  337. X.I ckd 
  338. from your 
  339. X.I .login 
  340. file, it will terminate shortly after you logout.
  341. X
  342. X.I ck 
  343. normally prints to the standard output, and 
  344. X.I ckd 
  345. to the standard error.  This can be changed via the 
  346. X.B \-o 
  347. option described below.  
  348. X.I ckd
  349. will try to ring the bell on the output device whenever it
  350. detects new mail.
  351. X
  352. X.SH OPTIONS
  353. X.TP
  354. X.B \-v
  355. After listing the contents of the mailbox, display its size and
  356. time of modification.
  357. X.TP
  358. X.BI \-o " outfile"
  359. Redirect output to the file or device specified by 
  360. X.I outfile.  
  361. If the file already exists, the output is appended to it.
  362. X.TP
  363. X.BI \-i interval
  364. Check the mailbox every 
  365. X.I interval 
  366. seconds instead of the default, 120.  This option is only meaningful
  367. in 
  368. X.IR ckd .  
  369. X
  370. X.SH FILES
  371. X.TP
  372. X.B $HOME/mailbox
  373. default mailbox file to monitor
  374. X
  375. X.SH DIAGNOSTICS
  376. XExit status is -1 if the file specified in the 
  377. X.B \-o 
  378. option can't be opened.  Otherwise, 
  379. X.IR ck 's 
  380. exit status is equal to the number of messages found in the
  381. mailbox, and 
  382. X.IR ckd 's 
  383. is 0.
  384. X
  385. X
  386. X.SH BUGS
  387. Only handles MMDF format files.
  388. X
  389. There should be an option to turn the bell on or off.
  390. X
  391. Ckd should be smarter about reporting changes in the file.  Right
  392. now it announces any change which leaves messages in the file (even
  393. deleting some messages).  A better approach would be to do some
  394. smart-work to see if it looks like new messages were added.
  395. X
  396. X.SH AUTHOR
  397. X
  398. Wayne Mesard, MESARD@BBN.COM
  399. X
  400. END_OF_FILE
  401. if test 3012 -ne `wc -c <'ck.man'`; then
  402.     echo shar: \"'ck.man'\" unpacked with wrong size!
  403. fi
  404. # end of 'ck.man'
  405. fi
  406. if test -f 'ckd.man' -a "${1}" != "-c" ; then 
  407.   echo shar: Will not clobber existing file \"'ckd.man'\"
  408. else
  409. echo shar: Extracting \"'ckd.man'\" \(14 characters\)
  410. sed "s/^X//" >'ckd.man' <<'END_OF_FILE'
  411. X.so man1/ck.1
  412. END_OF_FILE
  413. if test 14 -ne `wc -c <'ckd.man'`; then
  414.     echo shar: \"'ckd.man'\" unpacked with wrong size!
  415. fi
  416. # end of 'ckd.man'
  417. fi
  418. if test -f 'wsm_types.h' -a "${1}" != "-c" ; then 
  419.   echo shar: Will not clobber existing file \"'wsm_types.h'\"
  420. else
  421. echo shar: Extracting \"'wsm_types.h'\" \(437 characters\)
  422. sed "s/^X//" >'wsm_types.h' <<'END_OF_FILE'
  423. X/**
  424. X ** ADT: LIFO queue of int's
  425. X **/
  426. X
  427. X#ifndef LIFO_Q_SIZE
  428. X#define LIFO_Q_SIZE 20
  429. X#endif
  430. X
  431. typedef struct {
  432. X  int q[LIFO_Q_SIZE];
  433. X  int ptr;
  434. X} lifo;
  435. X
  436. X#define Q_init(QQ) QQ.ptr = 0
  437. X#define Q_pop(QQ) QQ.q[(--QQ.ptr)]
  438. X#define Q_peek(QQ) QQ.q[(QQ.ptr-1)]
  439. X#define Q_push(QQ, DATA) QQ.q[QQ.ptr]=DATA, QQ.ptr=((QQ.ptr+1)%LIFO_Q_SIZE)
  440. X#define Q_size(QQ) QQ.ptr
  441. X
  442. X
  443. X
  444. X/**
  445. X ** ADT: boolean
  446. X **/
  447. X
  448. X#define boolean    short
  449. X#define true    1
  450. X#define false    0
  451. X
  452. X
  453. END_OF_FILE
  454. if test 437 -ne `wc -c <'wsm_types.h'`; then
  455.     echo shar: \"'wsm_types.h'\" unpacked with wrong size!
  456. fi
  457. # end of 'wsm_types.h'
  458. fi
  459. echo shar: End of shell archive.
  460. exit 0
  461.